package webport_sp1

import (
	"fmt"
	"io"
	"log"
	"net"
	"runtime/debug"
	"sync"
)

// struct for handling connection forwarding
type forwarder struct {
	stream net.Conn
	conn   net.Conn
	port   int
	notify func()
}

// forwards multiplexed stream to port
func (f *forwarder) forward() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("panic: %v\n", r)
			fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
		}
	}()

	var err error

	// read port (uint32be) from stream
	serverIdBuf := make([]byte, 4)
	_, err = io.ReadFull(f.stream, serverIdBuf)
	if err != nil {
		log.Printf("webport_sp2: failed to read port: %v", err)
		f.stream.Close()
		return
	}

	f.port = int(serverIdBuf[2])*256 + int(serverIdBuf[3])

	if f.port == 0 {
		log.Printf("webport_sp2: unknown port: %d", f.port)
		f.stream.Close()
		return
	}

	serverAddr := fmt.Sprintf("127.0.0.1:%d", f.port)
	f.conn, err = net.Dial("tcp", serverAddr)

	// defer f.notify()

	// just to be sure
	defer f.kill()

	if err != nil {
		return
	}

	var wg sync.WaitGroup

	wg.Add(2)

	// outgoing stream (local -> backend service)
	go func() {
		defer wg.Done()
		_, _ = io.Copy(f.stream, f.conn)
		_ = f.stream.Close()
		f.stream = nil
	}()

	// incoming stream (backend service -> local)
	go func() {
		defer wg.Done()
		_, _ = io.Copy(f.conn, f.stream)
		_ = f.conn.Close()
		f.conn = nil
	}()

	wg.Wait()
}

func (f *forwarder) kill() {
	if f.stream != nil {
		_ = f.stream.Close()
		f.stream = nil
	}

	if f.conn != nil {
		_ = f.conn.Close()
		f.conn = nil
	}
}
